﻿using HalconDotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using thinger.VisionModels;

namespace thinger.VisitionDAL
{
   
    public class ToolsHelper
    {

        private HalconHelper halcon = new HalconHelper();

        private ShapeModelHelper shapeModel = new ShapeModelHelper();


        public bool FindMaxRegion(HObject Image, HObject Region, HTuple MinGray, HTuple MaxGray, out HObject RegionOut)
        {
            HOperatorSet.GenEmptyObj(out RegionOut);
            try
            {
                HObject ho_ImageReduced, ho_Region;
                HOperatorSet.GenEmptyObj(out ho_ImageReduced);
                HOperatorSet.GenEmptyObj(out ho_Region);

                ho_ImageReduced.Dispose();
                HOperatorSet.ReduceDomain(Image, Region, out ho_ImageReduced);
                ho_Region.Dispose();
                HOperatorSet.Threshold(ho_ImageReduced, out ho_Region, MinGray, MaxGray);
                {
                    HObject ExpTmpOutVar_0;
                    HOperatorSet.ClosingCircle(ho_Region, out ExpTmpOutVar_0, 25.5);
                    ho_Region.Dispose();
                    ho_Region = ExpTmpOutVar_0;
                }
                {
                    HObject ExpTmpOutVar_0;
                    HOperatorSet.Connection(ho_Region, out ExpTmpOutVar_0);
                    ho_Region.Dispose();
                    ho_Region = ExpTmpOutVar_0;
                }
                {
                    HObject ExpTmpOutVar_0;
                    HOperatorSet.FillUp(ho_Region, out ExpTmpOutVar_0);
                    ho_Region.Dispose();
                    ho_Region = ExpTmpOutVar_0;
                }
                {
                    HObject ExpTmpOutVar_0;
                    HOperatorSet.OpeningCircle(ho_Region, out ExpTmpOutVar_0, 27.5);
                    ho_Region.Dispose();
                    ho_Region = ExpTmpOutVar_0;
                }
                {
                    HOperatorSet.SelectShapeStd(ho_Region, out RegionOut, "max_area", 70);
                    ho_Region.Dispose();
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }

        }


        /// <summary>
        /// 拟合圆过程
        /// </summary>
        /// <param name="image"></param>
        /// <param name="circleParams"></param>
        /// <param name="hRegion"></param>
        /// <param name="result_Circle"></param>
        /// <param name="hv_RowCenter"></param>
        /// <param name="hv_ColCenter"></param>
        /// <param name="hv_Radius"></param>
        /// <param name="hv_StartPhi"></param>
        /// <param name="hv_EndPhi"></param>
        /// <param name="hv_PointOrder"></param>
        /// <param name="hv_ArcAngle"></param>
        /// <returns></returns>
        public OperateResult Fit_Circle(HObject image, HTuple homMat2d, ref CircleParams circleParams, out HObject result_Circle)
        {
            result_Circle = new HObject();
            try
            {
                HTuple resultRow, resultCol, resultArcType;

                //需要先将圆ROI做仿射变换

                //需要做仿射变换
                if (homMat2d.Length > 1)
                {
                    HTuple ROIXNew, ROIYNew;

                    HOperatorSet.AffineTransPoint2d(homMat2d, circleParams.rOI_Y, circleParams.rOI_X, out ROIYNew, out ROIXNew);

                    //最终生成的是很多个边缘点
                    halcon.spoke(image, out HObject hRegion, circleParams.circle_Elements, circleParams.circle_Caliper_Height, circleParams.circle_Caliper_Width,

                        circleParams.circle_Sigma, circleParams.circle_Threshold, circleParams.circle_Transition, circleParams.circle_Point_Select, ROIYNew,

                        ROIXNew, circleParams.circle_Direct, out resultRow, out resultCol, out resultArcType);
                }

                //不需要做仿射变换
                else
                {
                    //最终生成的是很多个边缘点
                    halcon.spoke(image, out HObject hRegion, circleParams.circle_Elements, circleParams.circle_Caliper_Height, circleParams.circle_Caliper_Width,

                        circleParams.circle_Sigma, circleParams.circle_Threshold, circleParams.circle_Transition, circleParams.circle_Point_Select, circleParams.rOI_Y,

                        circleParams.rOI_X, circleParams.circle_Direct, out resultRow, out resultCol, out resultArcType);
                }
                //找到的边缘点个数是否满足条件
                if (resultRow.Length > circleParams.circle_Min_Points_Num)
                {
                    //显示边缘点
                    HOperatorSet.GenCrossContourXld(out HObject cross, resultRow, resultCol, 20, new HTuple(45));

                    halcon.pts_to_best_circle(out result_Circle, resultRow, resultCol, circleParams.circle_Min_Points_Num, resultArcType, out circleParams.circleCenter_X, out circleParams.circleCenter_Y,
                out circleParams.circleRadius, out HTuple hv_StartPhi, out HTuple hv_EndPhi, out HTuple hv_PointOrder,
                out HTuple hv_ArcAngle);

                    return new OperateResult()
                    {
                        IsSuccess = true,
                        Message = "拟合圆成功"
                    };
                }
                else
                {
                    return new OperateResult()
                    {
                        IsSuccess = false,
                        Message = "拟合圆找到的边缘点个数太少"
                    };
                }
            }
            catch (Exception ex)
            {
                return new OperateResult()
                {
                    IsSuccess = false,
                    Message = "拟合圆失败" + ex.Message
                };
            }
        }

        /// <summary>
        /// 查找圆
        /// </summary>
        /// <param name="hWindowHandle"></param>
        /// <param name="hImage"></param>
        /// <param name="matchParams"></param>
        /// <param name="circleParams"></param>
        /// <returns></returns>
        public OperateResult FindCircle(HTuple hWindowHandle, HObject hImage, MatchParams matchParams, ref CircleParams circleParams)
        {
            try
            {
                HTuple ResultStr = new HTuple();

                //模板查找

                var result = shapeModel.FindShapeModel(hWindowHandle, hImage, matchParams, out HTuple homMat2D);

                if (result.IsSuccess == false)
                {
                    halcon.disp_message(hWindowHandle, result.Message, "window", 20, 20, "red", "false");

                    return result;
                }

                ResultStr = result.Message;

                //圆拟合

                result = Fit_Circle(hImage, homMat2D, ref circleParams, out HObject result_circle);

                if (result.IsSuccess == false)
                {
                    halcon.disp_message(hWindowHandle, result.Message, "window", 20, 20, "red", "false");

                    return result;
                }

                HOperatorSet.DispObj(result_circle, hWindowHandle);

                ResultStr = ResultStr.TupleConcat("查找圆成功");
                ResultStr = ResultStr.TupleConcat("圆心：" + circleParams.circleCenter_X + "," + circleParams.circleCenter_Y);

                return OperateResult.CreateSuccessResult();
            }
            catch (Exception ex)
            {
                return OperateResult.CreateFailResult("查找圆失败：" + ex.Message);
            }
        }


        /// <summary>
        /// 查找矩形
        /// </summary>
        /// <param name="hWindowHandle"></param>
        /// <param name="hImage"></param>
        /// <param name="matchParams"></param>
        /// <param name="circleParams"></param>
        /// <returns></returns>
        public OperateResult FindRec2(HTuple hWindowHandle, HObject hImage, MatchParams matchParams, ref CaliperParam caliperParam)
        {
            try
            {
                HTuple ResultStr = new HTuple();

                //模板查找
                var result = shapeModel.FindShapeModel(hWindowHandle, hImage, matchParams, out matchParams.homMat2D);

                if (result.IsSuccess == false)
                {
                    halcon.disp_message(hWindowHandle, result.Message, "window", 20, 20, "red", "false");

                    return result;
                }

                //Blob处理
                ResultStr = result.Message;
                HObject RegionT;
                if (matchParams.homMat2D.Length > 0)
                {
                    HOperatorSet.AffineTransRegion(matchParams.modelRegion, out RegionT, matchParams.homMat2D, "nearest_neighbor");
                }
                else
                {
                    HOperatorSet.CopyObj(matchParams.modelRegion, out RegionT, 1, -1);
                }

                FindMaxRegion(hImage, RegionT, 0, caliperParam.BloBThrehold, out caliperParam.BlobRegion);

                //矩形拟合

                result = FitRect2(hImage, ref caliperParam, out HObject contourOut, out HObject result_circle);

                if (result.IsSuccess == false)
                {
                    halcon.disp_message(hWindowHandle, result.Message, "window", 20, 20, "red", "false");

                    return result;
                }

                HOperatorSet.DispObj(result_circle, hWindowHandle);

                ResultStr = ResultStr.TupleConcat("查找矩形成功");
                ResultStr = ResultStr.TupleConcat("中心角度：" + caliperParam.ResultCenterX + "," + caliperParam.ResultCenterX + "," + caliperParam.ResultA);

                return OperateResult.CreateSuccessResult();
            }
            catch (Exception ex)
            {
                return OperateResult.CreateFailResult("查找矩形失败：" + ex.Message);
            }
        }

        public OperateResult FitRect2(HObject hImage, ref CaliperParam caliperParam, out HObject contourOut, out HObject regionsOut)
        {
            HOperatorSet.GenEmptyObj(out contourOut);
            HOperatorSet.GenEmptyObj(out regionsOut);
            try
            {
                HTuple hv_CornerYOut = new HTuple(),
                    hv_CornerXOut = new HTuple(),
                    hv_LineCenterYOut = new HTuple(),
                    hv_LineCenterXOut = new HTuple(),
                    hv_WidthOut = new HTuple(),
                    hv_HeightOut = new HTuple(),
                    hv_ExceptionOut = new HTuple();
                contourOut.Dispose();
                regionsOut.Dispose();

                region_to_rake_rectangle2(hImage, caliperParam.BlobRegion, out regionsOut, out contourOut,
                    caliperParam.CaliperElements, caliperParam.CaliperHeight,
                   caliperParam.CaliperWidth, caliperParam.CaliperSigma,
                    caliperParam.CaliperThreshold, caliperParam.CaliperTransition,
                    caliperParam.CaliperPointSelect, caliperParam.RefAngle,
                    out hv_CornerYOut, out hv_CornerXOut, out hv_LineCenterYOut,
                    out hv_LineCenterXOut, out caliperParam.ResultCenterY, out caliperParam.ResultCenterX, out caliperParam.ResultA,
                    out hv_WidthOut, out hv_HeightOut, out hv_ExceptionOut);
                if (hv_ExceptionOut.Length > 1)
                {
                    return OperateResult.CreateFailResult("拟合矩形出错");
                }
                else
                {
                    if (hv_ExceptionOut == 0)
                    {
                        return OperateResult.CreateSuccessResult();
                    }
                    else
                    {
                        return OperateResult.CreateFailResult("拟合矩形出错");
                    }
                }
            }
            catch (Exception)
            {
                return OperateResult.CreateFailResult("拟合矩形出错");
            }
        }

        public void region_to_rake_rectangle2(HObject ho_Image, HObject ho_Region, out HObject ho_RegionOut,
out HObject ho_ContourOut, HTuple hv_Elements, HTuple hv_DetectHeight, HTuple hv_DetectWidth,
HTuple hv_Sigma, HTuple hv_Threshold, HTuple hv_Tansition, HTuple hv_Select,
HTuple hv_RefAngle, out HTuple hv_CornerYOut, out HTuple hv_CornerXOut, out HTuple hv_LineCenterYOut,
out HTuple hv_LineCenterXOut, out HTuple hv_CenterYOut, out HTuple hv_CenterXOut,
out HTuple hv_AngleOut, out HTuple hv_WidthOut, out HTuple hv_HeightOut, out HTuple hv_ExceptionOut)
        {
            // Stack for temporary objects 
            HObject[] OTemp = new HObject[20];

            // Local iconic variables 

            HObject ho_ConnectedRegions1 = null, ho_RegionFillUp1 = null;
            HObject ho_SelectedRegions1 = null, ho_RegionOpening = null;
            HObject ho_RegionClosing = null, ho_Regions = null, ho_Line = null;
            HObject ho_Cross = null, ho_SortedContours = null, ho_Cross1 = null;

            // Local control variables 

            HTuple hv_Row = new HTuple(), hv_Column = new HTuple();
            HTuple hv_Phi = new HTuple(), hv_Length1 = new HTuple();
            HTuple hv_Length2 = new HTuple(), hv_Row1 = new HTuple();
            HTuple hv_Column1 = new HTuple(), hv_Phi1 = new HTuple();
            HTuple hv_Length11 = new HTuple(), hv_Length21 = new HTuple();
            HTuple hv_CornerY = new HTuple(), hv_CornerX = new HTuple();
            HTuple hv_LineCenterY = new HTuple(), hv_LineCenterX = new HTuple();
            HTuple hv_LineRow1 = new HTuple(), hv_LineCol1 = new HTuple();
            HTuple hv_LineRow2 = new HTuple(), hv_LineCol2 = new HTuple();
            HTuple hv_i = new HTuple(), hv_ResultRow = new HTuple();
            HTuple hv_ResultColumn = new HTuple(), hv_Row11 = new HTuple();
            HTuple hv_Column11 = new HTuple(), hv_Row2 = new HTuple();
            HTuple hv_Column2 = new HTuple(), hv_Row3 = new HTuple();
            HTuple hv_Column3 = new HTuple(), hv_IsParallel = new HTuple();
            HTuple hv_Col = new HTuple(), hv_Angle = new HTuple();
            HTuple hv_AngleDiffMin = new HTuple(), hv_AngleT0 = new HTuple();
            HTuple hv_AngleT1 = new HTuple(), hv_AngleT2 = new HTuple();
            HTuple hv_AngleT3 = new HTuple(), hv_AngleT = new HTuple();
            HTuple hv_Radius = new HTuple(), hv_Distance = new HTuple();
            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_RegionOut);
            HOperatorSet.GenEmptyObj(out ho_ContourOut);
            HOperatorSet.GenEmptyObj(out ho_ConnectedRegions1);
            HOperatorSet.GenEmptyObj(out ho_RegionFillUp1);
            HOperatorSet.GenEmptyObj(out ho_SelectedRegions1);
            HOperatorSet.GenEmptyObj(out ho_RegionOpening);
            HOperatorSet.GenEmptyObj(out ho_RegionClosing);
            HOperatorSet.GenEmptyObj(out ho_Regions);
            HOperatorSet.GenEmptyObj(out ho_Line);
            HOperatorSet.GenEmptyObj(out ho_Cross);
            HOperatorSet.GenEmptyObj(out ho_SortedContours);
            HOperatorSet.GenEmptyObj(out ho_Cross1);
            hv_CornerYOut = new HTuple();
            hv_CornerXOut = new HTuple();
            hv_LineCenterYOut = new HTuple();
            hv_LineCenterXOut = new HTuple();
            hv_CenterYOut = new HTuple();
            hv_CenterXOut = new HTuple();
            hv_AngleOut = new HTuple();
            hv_WidthOut = new HTuple();
            hv_HeightOut = new HTuple();
            hv_ExceptionOut = new HTuple();
            try
            {
                // (dev_)set_check ("give_error")
                try
                {
                    hv_ExceptionOut = 0;
                    //预处理，获取区域外接rect2的定点和边中点
                    ho_ConnectedRegions1.Dispose();
                    HOperatorSet.Connection(ho_Region, out ho_ConnectedRegions1);
                    ho_RegionFillUp1.Dispose();
                    HOperatorSet.FillUp(ho_ConnectedRegions1, out ho_RegionFillUp1);
                    ho_SelectedRegions1.Dispose();
                    HOperatorSet.SelectShapeStd(ho_RegionFillUp1, out ho_SelectedRegions1, "max_area",
                        70);
                    HOperatorSet.SmallestRectangle2(ho_SelectedRegions1, out hv_Row, out hv_Column,
                        out hv_Phi, out hv_Length1, out hv_Length2);
                    ho_RegionOpening.Dispose();
                    HOperatorSet.OpeningCircle(ho_SelectedRegions1, out ho_RegionOpening, hv_Length2 / 8);
                    ho_RegionClosing.Dispose();
                    HOperatorSet.ClosingCircle(ho_RegionOpening, out ho_RegionClosing, hv_Length2 / 6);
                    HOperatorSet.SmallestRectangle2(ho_RegionClosing, out hv_Row1, out hv_Column1,
                        out hv_Phi1, out hv_Length11, out hv_Length21);
                    get_rectangle2_points(hv_Row1, hv_Column1, hv_Phi1, hv_Length11, hv_Length21,
                        out hv_CornerY, out hv_CornerX, out hv_LineCenterY, out hv_LineCenterX);

                    //rake拟合4条直线
                    hv_LineRow1 = new HTuple();
                    hv_LineCol1 = new HTuple();
                    hv_LineRow2 = new HTuple();
                    hv_LineCol2 = new HTuple();
                    ho_RegionOut.Dispose();
                    HOperatorSet.GenEmptyObj(out ho_RegionOut);
                    for (hv_i = 0; (int)hv_i <= 3; hv_i = (int)hv_i + 1)
                    {
                        if ((int)(new HTuple(hv_i.TupleNotEqual(3))) != 0)
                        {
                            ho_Regions.Dispose();
                            rake(ho_Image, out ho_Regions, hv_Elements, hv_DetectHeight, hv_DetectWidth,
                                hv_Sigma, hv_Threshold, hv_Tansition, hv_Select, hv_CornerY.TupleSelect(
                                hv_i), hv_CornerX.TupleSelect(hv_i), hv_CornerY.TupleSelect(hv_i + 1),
                                hv_CornerX.TupleSelect(hv_i + 1), out hv_ResultRow, out hv_ResultColumn);
                        }
                        else
                        {
                            ho_Regions.Dispose();
                            rake(ho_Image, out ho_Regions, hv_Elements, hv_DetectHeight, hv_DetectWidth,
                                hv_Sigma, hv_Threshold, hv_Tansition, hv_Select, hv_CornerY.TupleSelect(
                                hv_i), hv_CornerX.TupleSelect(hv_i), hv_CornerY.TupleSelect(0), hv_CornerX.TupleSelect(
                                0), out hv_ResultRow, out hv_ResultColumn);
                        }
                        if ((int)(new HTuple((new HTuple(hv_ResultRow.TupleLength())).TupleLess(1))) != 0)
                        {
                            hv_ExceptionOut = "rake找边错误";
                            ho_ConnectedRegions1.Dispose();
                            ho_RegionFillUp1.Dispose();
                            ho_SelectedRegions1.Dispose();
                            ho_RegionOpening.Dispose();
                            ho_RegionClosing.Dispose();
                            ho_Regions.Dispose();
                            ho_Line.Dispose();
                            ho_Cross.Dispose();
                            ho_SortedContours.Dispose();
                            ho_Cross1.Dispose();

                            return;
                        }
                        {
                            HObject ExpTmpOutVar_0;
                            HOperatorSet.ConcatObj(ho_RegionOut, ho_Regions, out ExpTmpOutVar_0);
                            ho_RegionOut.Dispose();
                            ho_RegionOut = ExpTmpOutVar_0;
                        }
                        ho_Line.Dispose();
                        pts_to_best_line(out ho_Line, hv_ResultRow, hv_ResultColumn, 2, out hv_Row11,
                            out hv_Column11, out hv_Row2, out hv_Column2);

                        hv_LineRow1 = hv_LineRow1.TupleConcat(hv_Row11);
                        hv_LineCol1 = hv_LineCol1.TupleConcat(hv_Column11);
                        hv_LineRow2 = hv_LineRow2.TupleConcat(hv_Row2);
                        hv_LineCol2 = hv_LineCol2.TupleConcat(hv_Column2);
                    }

                    //求顶点
                    hv_CornerYOut = new HTuple();
                    hv_CornerXOut = new HTuple();
                    for (hv_i = 0; (int)hv_i <= 3; hv_i = (int)hv_i + 1)
                    {
                        if ((int)(new HTuple(hv_i.TupleNotEqual(3))) != 0)
                        {
                            HOperatorSet.IntersectionLl(hv_LineRow1.TupleSelect(hv_i), hv_LineCol1.TupleSelect(
                                hv_i), hv_LineRow2.TupleSelect(hv_i), hv_LineCol2.TupleSelect(hv_i),
                                hv_LineRow1.TupleSelect(hv_i + 1), hv_LineCol1.TupleSelect(hv_i + 1),
                                hv_LineRow2.TupleSelect(hv_i + 1), hv_LineCol2.TupleSelect(hv_i + 1),
                                out hv_Row3, out hv_Column3, out hv_IsParallel);
                        }
                        else
                        {
                            HOperatorSet.IntersectionLl(hv_LineRow1.TupleSelect(hv_i), hv_LineCol1.TupleSelect(
                                hv_i), hv_LineRow2.TupleSelect(hv_i), hv_LineCol2.TupleSelect(hv_i),
                                hv_LineRow1.TupleSelect(0), hv_LineCol1.TupleSelect(0), hv_LineRow2.TupleSelect(
                                0), hv_LineCol2.TupleSelect(0), out hv_Row3, out hv_Column3, out hv_IsParallel);
                        }

                        hv_CornerYOut = hv_CornerYOut.TupleConcat(hv_Row3);
                        hv_CornerXOut = hv_CornerXOut.TupleConcat(hv_Column3);

                    }

                    //求边中点
                    hv_LineCenterYOut = new HTuple();
                    hv_LineCenterXOut = new HTuple();
                    for (hv_i = 0; (int)hv_i <= 3; hv_i = (int)hv_i + 1)
                    {
                        if ((int)(new HTuple(hv_i.TupleNotEqual(3))) != 0)
                        {
                            hv_Row = 0.5 * ((hv_CornerYOut.TupleSelect(hv_i)) + (hv_CornerYOut.TupleSelect(
                                hv_i + 1)));
                            hv_Col = 0.5 * ((hv_CornerXOut.TupleSelect(hv_i)) + (hv_CornerXOut.TupleSelect(
                                hv_i + 1)));
                        }
                        else
                        {
                            hv_Row = 0.5 * ((hv_CornerYOut.TupleSelect(hv_i)) + (hv_CornerYOut.TupleSelect(
                                0)));
                            hv_Col = 0.5 * ((hv_CornerXOut.TupleSelect(hv_i)) + (hv_CornerXOut.TupleSelect(
                                0)));
                        }
                        hv_LineCenterYOut = hv_LineCenterYOut.TupleConcat(hv_Row);
                        hv_LineCenterXOut = hv_LineCenterXOut.TupleConcat(hv_Col);
                    }

                    //通过边中点连线的角度确定rect2角度
                    hv_Angle = new HTuple();
                    hv_AngleOut = new HTuple();
                    hv_AngleDiffMin = 360;
                    //求对边中点连线的角度，直线是矢量，a->b和b->a两个角度
                    HOperatorSet.AngleLx(hv_LineCenterYOut.TupleSelect(0), hv_LineCenterXOut.TupleSelect(
                        0), hv_LineCenterYOut.TupleSelect(2), hv_LineCenterXOut.TupleSelect(2),
                        out hv_AngleT0);
                    HOperatorSet.AngleLx(hv_LineCenterYOut.TupleSelect(2), hv_LineCenterXOut.TupleSelect(
                        2), hv_LineCenterYOut.TupleSelect(0), hv_LineCenterXOut.TupleSelect(0),
                        out hv_AngleT1);
                    HOperatorSet.AngleLx(hv_LineCenterYOut.TupleSelect(1), hv_LineCenterXOut.TupleSelect(
                        1), hv_LineCenterYOut.TupleSelect(3), hv_LineCenterXOut.TupleSelect(3),
                        out hv_AngleT2);
                    HOperatorSet.AngleLx(hv_LineCenterYOut.TupleSelect(3), hv_LineCenterXOut.TupleSelect(
                        3), hv_LineCenterYOut.TupleSelect(1), hv_LineCenterXOut.TupleSelect(1),
                        out hv_AngleT3);
                    //求与参考角度夹角最小的角度作为输出
                    hv_AngleT = new HTuple();
                    hv_AngleT = hv_AngleT.TupleConcat(hv_AngleT0);
                    hv_AngleT = hv_AngleT.TupleConcat(hv_AngleT1);
                    hv_AngleT = hv_AngleT.TupleConcat(hv_AngleT2);
                    hv_AngleT = hv_AngleT.TupleConcat(hv_AngleT3);
                    for (hv_i = 0; (int)hv_i <= 3; hv_i = (int)hv_i + 1)
                    {
                        hv_Angle = hv_Angle.TupleConcat(((hv_RefAngle - (((hv_AngleT.TupleSelect(
                            hv_i))).TupleDeg()))).TupleAbs());
                        if ((int)(new HTuple(((((hv_RefAngle - (((hv_AngleT.TupleSelect(hv_i))).TupleDeg()
                            ))).TupleAbs())).TupleLessEqual(hv_AngleDiffMin))) != 0)
                        {
                            hv_AngleDiffMin = ((hv_RefAngle - (((hv_AngleT.TupleSelect(hv_i))).TupleDeg()
                                ))).TupleAbs();
                            hv_AngleOut = ((hv_AngleT.TupleSelect(hv_i))).TupleDeg();
                        }
                    }

                    //求rect2中心
                    HOperatorSet.TupleMean(hv_CornerYOut, out hv_CenterYOut);
                    HOperatorSet.TupleMean(hv_CornerXOut, out hv_CenterXOut);

                    //求高度（垂直方向作为高度）和宽度（水平方向作为宽度）
                    ho_Cross.Dispose();
                    HOperatorSet.GenCrossContourXld(out ho_Cross, hv_CornerYOut, hv_CornerXOut,
                        2, 0);
                    ho_SortedContours.Dispose();
                    HOperatorSet.SortContoursXld(ho_Cross, out ho_SortedContours, "upper_left",
                        "true", "row");
                    HOperatorSet.SmallestCircleXld(ho_SortedContours, out hv_Row, out hv_Column,
                        out hv_Radius);
                    HOperatorSet.DistancePl(hv_Row.TupleSelectRange(0, 1), hv_Column.TupleSelectRange(
                        0, 1), hv_Row.TupleSelect(2), hv_Column.TupleSelect(2), hv_Row.TupleSelect(
                        3), hv_Column.TupleSelect(3), out hv_Distance);
                    HOperatorSet.TupleMean(hv_Distance, out hv_HeightOut);

                    ho_SortedContours.Dispose();
                    HOperatorSet.SortContoursXld(ho_Cross, out ho_SortedContours, "upper_left",
                        "true", "column");
                    HOperatorSet.SmallestCircleXld(ho_SortedContours, out hv_Row, out hv_Column,
                        out hv_Radius);
                    HOperatorSet.DistancePl(hv_Row.TupleSelectRange(0, 1), hv_Column.TupleSelectRange(
                        0, 1), hv_Row.TupleSelect(2), hv_Column.TupleSelect(2), hv_Row.TupleSelect(
                        3), hv_Column.TupleSelect(3), out hv_Distance);
                    HOperatorSet.TupleMean(hv_Distance, out hv_WidthOut);

                    //产生拟合的矩形
                    ho_ContourOut.Dispose();
                    HOperatorSet.GenContourPolygonXld(out ho_ContourOut, hv_CornerYOut.TupleConcat(
                        hv_CornerYOut.TupleSelect(0)), hv_CornerXOut.TupleConcat(hv_CornerXOut.TupleSelect(
                        0)));
                    ho_Cross1.Dispose();
                    HOperatorSet.GenCrossContourXld(out ho_Cross1, hv_CenterYOut, hv_CenterXOut,
                        12, 0);
                    {
                        HObject ExpTmpOutVar_0;
                        HOperatorSet.ConcatObj(ho_ContourOut, ho_Cross1, out ExpTmpOutVar_0);
                        ho_ContourOut.Dispose();
                        ho_ContourOut = ExpTmpOutVar_0;
                    }
                }
                // catch (ExceptionOut) 
                catch (HalconException HDevExpDefaultException1)
                {
                    HDevExpDefaultException1.ToHTuple(out hv_ExceptionOut);
                }
                ho_ConnectedRegions1.Dispose();
                ho_RegionFillUp1.Dispose();
                ho_SelectedRegions1.Dispose();
                ho_RegionOpening.Dispose();
                ho_RegionClosing.Dispose();
                ho_Regions.Dispose();
                ho_Line.Dispose();
                ho_Cross.Dispose();
                ho_SortedContours.Dispose();
                ho_Cross1.Dispose();

                return;
            }
            catch (HalconException HDevExpDefaultException)
            {
                ho_ConnectedRegions1.Dispose();
                ho_RegionFillUp1.Dispose();
                ho_SelectedRegions1.Dispose();
                ho_RegionOpening.Dispose();
                ho_RegionClosing.Dispose();
                ho_Regions.Dispose();
                ho_Line.Dispose();
                ho_Cross.Dispose();
                ho_SortedContours.Dispose();
                ho_Cross1.Dispose();

                throw HDevExpDefaultException;
            }
        }

        public void get_rectangle2_points(HTuple hv_CenterY, HTuple hv_CenterX, HTuple hv_Phi,
    HTuple hv_Len1, HTuple hv_Len2, out HTuple hv_CornerY, out HTuple hv_CornerX,
    out HTuple hv_LineCenterY, out HTuple hv_LineCenterX)
        {
            // Local iconic variables 

            // Local control variables 

            HTuple hv_RowT = null, hv_ColT = null, hv_Cos = null;
            HTuple hv_Sin = null;
            // Initialize local and output iconic variables 
            //矩形端点坐标变量、边中心坐标变量初始化
            hv_CornerX = new HTuple();
            hv_CornerY = new HTuple();
            hv_LineCenterX = new HTuple();
            hv_LineCenterY = new HTuple();

            //临时变量初始化
            hv_RowT = 0;
            hv_ColT = 0;

            //判断仿射矩形是否有效
            if ((int)((new HTuple(hv_Len1.TupleLessEqual(0))).TupleOr(new HTuple(hv_Len2.TupleLessEqual(
                0)))) != 0)
            {

                return;
            }

            //计算仿射矩形角度的正弦值、余弦值
            HOperatorSet.TupleCos(hv_Phi, out hv_Cos);
            HOperatorSet.TupleSin(hv_Phi, out hv_Sin);

            //矩形第一个端点坐标
            hv_ColT = (hv_CenterX - (hv_Len1 * hv_Cos)) - (hv_Len2 * hv_Sin);
            hv_RowT = hv_CenterY - (((-hv_Len1) * hv_Sin) + (hv_Len2 * hv_Cos));
            hv_CornerY = hv_CornerY.TupleConcat(hv_RowT);
            hv_CornerX = hv_CornerX.TupleConcat(hv_ColT);

            //矩形第二个端点坐标
            hv_ColT = (hv_CenterX + (hv_Len1 * hv_Cos)) - (hv_Len2 * hv_Sin);
            hv_RowT = hv_CenterY - ((hv_Len1 * hv_Sin) + (hv_Len2 * hv_Cos));
            hv_CornerY = hv_CornerY.TupleConcat(hv_RowT);
            hv_CornerX = hv_CornerX.TupleConcat(hv_ColT);

            //矩形第三个端点坐标
            hv_ColT = (hv_CenterX + (hv_Len1 * hv_Cos)) + (hv_Len2 * hv_Sin);
            hv_RowT = hv_CenterY - ((hv_Len1 * hv_Sin) - (hv_Len2 * hv_Cos));
            hv_CornerY = hv_CornerY.TupleConcat(hv_RowT);
            hv_CornerX = hv_CornerX.TupleConcat(hv_ColT);

            //矩形第四个端点坐标
            hv_ColT = (hv_CenterX - (hv_Len1 * hv_Cos)) + (hv_Len2 * hv_Sin);
            hv_RowT = hv_CenterY - (((-hv_Len1) * hv_Sin) - (hv_Len2 * hv_Cos));
            hv_CornerY = hv_CornerY.TupleConcat(hv_RowT);
            hv_CornerX = hv_CornerX.TupleConcat(hv_ColT);

            //矩形第一条边中心坐标
            if (hv_LineCenterY == null)
                hv_LineCenterY = new HTuple();
            hv_LineCenterY[0] = ((hv_CornerY.TupleSelect(0)) + (hv_CornerY.TupleSelect(1))) * 0.5;
            if (hv_LineCenterX == null)
                hv_LineCenterX = new HTuple();
            hv_LineCenterX[0] = ((hv_CornerX.TupleSelect(0)) + (hv_CornerX.TupleSelect(1))) * 0.5;

            //矩形第二条边中心坐标
            if (hv_LineCenterY == null)
                hv_LineCenterY = new HTuple();
            hv_LineCenterY[1] = ((hv_CornerY.TupleSelect(1)) + (hv_CornerY.TupleSelect(2))) * 0.5;
            if (hv_LineCenterX == null)
                hv_LineCenterX = new HTuple();
            hv_LineCenterX[1] = ((hv_CornerX.TupleSelect(1)) + (hv_CornerX.TupleSelect(2))) * 0.5;

            //矩形第三条边中心坐标
            if (hv_LineCenterY == null)
                hv_LineCenterY = new HTuple();
            hv_LineCenterY[2] = ((hv_CornerY.TupleSelect(3)) + (hv_CornerY.TupleSelect(2))) * 0.5;
            if (hv_LineCenterX == null)
                hv_LineCenterX = new HTuple();
            hv_LineCenterX[2] = ((hv_CornerX.TupleSelect(3)) + (hv_CornerX.TupleSelect(2))) * 0.5;

            //矩形第四边中心坐标
            if (hv_LineCenterY == null)
                hv_LineCenterY = new HTuple();
            hv_LineCenterY[3] = ((hv_CornerY.TupleSelect(3)) + (hv_CornerY.TupleSelect(0))) * 0.5;
            if (hv_LineCenterX == null)
                hv_LineCenterX = new HTuple();
            hv_LineCenterX[3] = ((hv_CornerX.TupleSelect(3)) + (hv_CornerX.TupleSelect(0))) * 0.5;

            //返回

            return;
        }


        public void pts_to_best_line(out HObject ho_Line, HTuple hv_Rows, HTuple hv_Cols,
       HTuple hv_ActiveNum, out HTuple hv_Row1, out HTuple hv_Column1, out HTuple hv_Row2,
       out HTuple hv_Column2)
        {
            // Local iconic variables 

            HObject ho_Contour = null;


            // Local control variables 

            HTuple hv_Length, hv_Nr = new HTuple(), hv_Nc = new HTuple();
            HTuple hv_Dist = new HTuple(), hv_Length1 = new HTuple();

            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_Line);
            HOperatorSet.GenEmptyObj(out ho_Contour);

            try
            {
                //初始化
                hv_Row1 = 0;
                hv_Column1 = 0;
                hv_Row2 = 0;
                hv_Column2 = 0;
                //产生一个空的直线对象，用于保存拟合后的直线
                ho_Line.Dispose();
                HOperatorSet.GenEmptyObj(out ho_Line);
                //计算边缘数量
                HOperatorSet.TupleLength(hv_Cols, out hv_Length);
                //当边缘数量不小于有效点数时进行拟合
                if ((int)((new HTuple(hv_Length.TupleGreaterEqual(hv_ActiveNum))).TupleAnd(
                    new HTuple(hv_ActiveNum.TupleGreater(1)))) != 0)
                {
                    //halcon的拟合是基于xld的，需要把边缘连接成xld
                    ho_Contour.Dispose();
                    HOperatorSet.GenContourPolygonXld(out ho_Contour, hv_Rows, hv_Cols);
                    //拟合直线。使用的算法是'tukey'，其他算法请参考fit_line_contour_xld的描述部分。
                    HOperatorSet.FitLineContourXld(ho_Contour, "tukey", -1, 0, 5, 2, out hv_Row1,
                        out hv_Column1, out hv_Row2, out hv_Column2, out hv_Nr, out hv_Nc, out hv_Dist);
                    //判断拟合结果是否有效：如果拟合成功，数组中元素的数量大于0
                    HOperatorSet.TupleLength(hv_Dist, out hv_Length1);
                    if ((int)(new HTuple(hv_Length1.TupleLess(1))) != 0)
                    {
                        ho_Contour.Dispose();

                        return;
                    }
                    //根据拟合结果，产生直线xld
                    ho_Line.Dispose();
                    HOperatorSet.GenContourPolygonXld(out ho_Line, hv_Row1.TupleConcat(hv_Row2),
                        hv_Column1.TupleConcat(hv_Column2));
                }

                ho_Contour.Dispose();

                return;
            }
            catch (HalconException HDevExpDefaultException)
            {
                ho_Contour.Dispose();

                throw HDevExpDefaultException;
            }
        }

        public void rake(HObject ho_Image, out HObject ho_Regions, HTuple hv_Elements,
            HTuple hv_DetectHeight, HTuple hv_DetectWidth, HTuple hv_Sigma, HTuple hv_Threshold,
            HTuple hv_Transition, HTuple hv_Select, HTuple hv_Row1, HTuple hv_Column1, HTuple hv_Row2,
            HTuple hv_Column2, out HTuple hv_ResultRow, out HTuple hv_ResultColumn)
        {

            // Stack for temporary objects 
            HObject[] OTemp = new HObject[20];
            long SP_O = 0;

            // Local iconic variables 

            HObject ho_RegionLines, ho_Rectangle = null;
            HObject ho_Arrow1 = null;


            // Local control variables 

            HTuple hv_Width, hv_Height, hv_ATan, hv_i;
            HTuple hv_RowC = new HTuple(), hv_ColC = new HTuple(), hv_Distance = new HTuple();
            HTuple hv_RowL2 = new HTuple(), hv_RowL1 = new HTuple(), hv_ColL2 = new HTuple();
            HTuple hv_ColL1 = new HTuple(), hv_MsrHandle_Measure = new HTuple();
            HTuple hv_RowEdge = new HTuple(), hv_ColEdge = new HTuple();
            HTuple hv_Amplitude = new HTuple(), hv_tRow = new HTuple();
            HTuple hv_tCol = new HTuple(), hv_t = new HTuple(), hv_Number = new HTuple();
            HTuple hv_j = new HTuple();

            HTuple hv_DetectWidth_COPY_INP_TMP = hv_DetectWidth.Clone();
            HTuple hv_Select_COPY_INP_TMP = hv_Select.Clone();
            HTuple hv_Transition_COPY_INP_TMP = hv_Transition.Clone();

            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_Regions);
            HOperatorSet.GenEmptyObj(out ho_RegionLines);
            HOperatorSet.GenEmptyObj(out ho_Rectangle);
            HOperatorSet.GenEmptyObj(out ho_Arrow1);

            try
            {
                //获取图像尺寸
                HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height);
                //产生一个空显示对象，用于显示
                ho_Regions.Dispose();
                HOperatorSet.GenEmptyObj(out ho_Regions);
                //初始化边缘坐标数组
                hv_ResultRow = new HTuple();
                hv_ResultColumn = new HTuple();
                //产生直线xld
                ho_RegionLines.Dispose();
                HOperatorSet.GenContourPolygonXld(out ho_RegionLines, hv_Row1.TupleConcat(hv_Row2),
                    hv_Column1.TupleConcat(hv_Column2));
                //存储到显示对象
                OTemp[SP_O] = ho_Regions.CopyObj(1, -1);
                SP_O++;
                ho_Regions.Dispose();
                HOperatorSet.ConcatObj(OTemp[SP_O - 1], ho_RegionLines, out ho_Regions);
                OTemp[SP_O - 1].Dispose();
                SP_O = 0;
                //计算直线与x轴的夹角，逆时针方向为正向。
                HOperatorSet.AngleLx(hv_Row1, hv_Column1, hv_Row2, hv_Column2, out hv_ATan);

                //边缘检测方向垂直于检测直线：直线方向正向旋转90°为边缘检测方向
                hv_ATan = hv_ATan + ((new HTuple(90)).TupleRad());

                //根据检测直线按顺序产生测量区域矩形，并存储到显示对象
                for (hv_i = 1; hv_i.Continue(hv_Elements, 1); hv_i = hv_i.TupleAdd(1))
                {
                    //RowC := Row1+(((Row2-Row1)*i)/(Elements+1))
                    //ColC := Column1+(Column2-Column1)*i/(Elements+1)
                    //if (RowC>Height-1 or RowC<0 or ColC>Width-1 or ColC<0)
                    //continue
                    //endif
                    //如果只有一个测量矩形，作为卡尺工具，宽度为检测直线的长度
                    if ((int)(new HTuple(hv_Elements.TupleEqual(1))) != 0)
                    {
                        hv_RowC = (hv_Row1 + hv_Row2) * 0.5;
                        hv_ColC = (hv_Column1 + hv_Column2) * 0.5;
                        //判断是否超出图像,超出不检测边缘
                        if ((int)((new HTuple((new HTuple((new HTuple(hv_RowC.TupleGreater(hv_Height - 1))).TupleOr(
                            new HTuple(hv_RowC.TupleLess(0))))).TupleOr(new HTuple(hv_ColC.TupleGreater(
                            hv_Width - 1))))).TupleOr(new HTuple(hv_ColC.TupleLess(0)))) != 0)
                        {
                            continue;
                        }
                        HOperatorSet.DistancePp(hv_Row1, hv_Column1, hv_Row2, hv_Column2, out hv_Distance);
                        hv_DetectWidth_COPY_INP_TMP = hv_Distance.Clone();
                        ho_Rectangle.Dispose();
                        HOperatorSet.GenRectangle2ContourXld(out ho_Rectangle, hv_RowC, hv_ColC,
                            hv_ATan, hv_DetectHeight / 2, hv_Distance / 2);
                    }
                    else
                    {
                        //如果有多个测量矩形，产生该测量矩形xld
                        hv_RowC = hv_Row1 + (((hv_Row2 - hv_Row1) * (hv_i - 1)) / (hv_Elements - 1));
                        hv_ColC = hv_Column1 + (((hv_Column2 - hv_Column1) * (hv_i - 1)) / (hv_Elements - 1));
                        //判断是否超出图像,超出不检测边缘
                        if ((int)((new HTuple((new HTuple((new HTuple(hv_RowC.TupleGreater(hv_Height - 1))).TupleOr(
                            new HTuple(hv_RowC.TupleLess(0))))).TupleOr(new HTuple(hv_ColC.TupleGreater(
                            hv_Width - 1))))).TupleOr(new HTuple(hv_ColC.TupleLess(0)))) != 0)
                        {
                            continue;
                        }
                        ho_Rectangle.Dispose();
                        HOperatorSet.GenRectangle2ContourXld(out ho_Rectangle, hv_RowC, hv_ColC,
                            hv_ATan, hv_DetectHeight / 2, hv_DetectWidth_COPY_INP_TMP / 2);
                    }

                    //把测量矩形xld存储到显示对象
                    OTemp[SP_O] = ho_Regions.CopyObj(1, -1);
                    SP_O++;
                    ho_Regions.Dispose();
                    HOperatorSet.ConcatObj(OTemp[SP_O - 1], ho_Rectangle, out ho_Regions);
                    OTemp[SP_O - 1].Dispose();
                    SP_O = 0;
                    if ((int)(new HTuple(hv_i.TupleEqual(1))) != 0)
                    {
                        //在第一个测量矩形绘制一个箭头xld，用于只是边缘检测方向
                        hv_RowL2 = hv_RowC + ((hv_DetectHeight / 2) * (((-hv_ATan)).TupleSin()));
                        hv_RowL1 = hv_RowC - ((hv_DetectHeight / 2) * (((-hv_ATan)).TupleSin()));
                        hv_ColL2 = hv_ColC + ((hv_DetectHeight / 2) * (((-hv_ATan)).TupleCos()));
                        hv_ColL1 = hv_ColC - ((hv_DetectHeight / 2) * (((-hv_ATan)).TupleCos()));
                        ho_Arrow1.Dispose();
                        gen_arrow_contour_xld(out ho_Arrow1, hv_RowL1, hv_ColL1, hv_RowL2, hv_ColL2,
                            25, 25);
                        //把xld存储到显示对象
                        OTemp[SP_O] = ho_Regions.CopyObj(1, -1);
                        SP_O++;
                        ho_Regions.Dispose();
                        HOperatorSet.ConcatObj(OTemp[SP_O - 1], ho_Arrow1, out ho_Regions);
                        OTemp[SP_O - 1].Dispose();
                        SP_O = 0;
                    }
                    //产生测量对象句柄
                    HOperatorSet.GenMeasureRectangle2(hv_RowC, hv_ColC, hv_ATan, hv_DetectHeight / 2,
                        hv_DetectWidth_COPY_INP_TMP / 2, hv_Width, hv_Height, "nearest_neighbor",
                        out hv_MsrHandle_Measure);

                    //设置极性
                    if ((int)(new HTuple(hv_Transition_COPY_INP_TMP.TupleEqual("negative"))) != 0)
                    {
                        hv_Transition_COPY_INP_TMP = "negative";
                    }
                    else
                    {
                        if ((int)(new HTuple(hv_Transition_COPY_INP_TMP.TupleEqual("positive"))) != 0)
                        {

                            hv_Transition_COPY_INP_TMP = "positive";
                        }
                        else
                        {
                            hv_Transition_COPY_INP_TMP = "all";
                        }
                    }
                    //设置边缘位置。最强点是从所有边缘中选择幅度绝对值最大点，需要设置为'all'
                    if ((int)(new HTuple(hv_Select_COPY_INP_TMP.TupleEqual("first"))) != 0)
                    {
                        hv_Select_COPY_INP_TMP = "first";
                    }
                    else
                    {
                        if ((int)(new HTuple(hv_Select_COPY_INP_TMP.TupleEqual("last"))) != 0)
                        {

                            hv_Select_COPY_INP_TMP = "last";
                        }
                        else
                        {
                            hv_Select_COPY_INP_TMP = "all";
                        }
                    }
                    //检测边缘
                    HOperatorSet.MeasurePos(ho_Image, hv_MsrHandle_Measure, hv_Sigma, hv_Threshold,
                        hv_Transition_COPY_INP_TMP, hv_Select_COPY_INP_TMP, out hv_RowEdge, out hv_ColEdge,
                        out hv_Amplitude, out hv_Distance);
                    //清除测量对象句柄
                    HOperatorSet.CloseMeasure(hv_MsrHandle_Measure);

                    //临时变量初始化
                    //tRow，tCol保存找到指定边缘的坐标
                    hv_tRow = 0;
                    hv_tCol = 0;
                    //t保存边缘的幅度绝对值
                    hv_t = 0;
                    //找到的边缘必须至少为1个
                    HOperatorSet.TupleLength(hv_RowEdge, out hv_Number);
                    if ((int)(new HTuple(hv_Number.TupleLess(1))) != 0)
                    {
                        continue;
                    }
                    //有多个边缘时，选择幅度绝对值最大的边缘
                    for (hv_j = 0; hv_j.Continue(hv_Number - 1, 1); hv_j = hv_j.TupleAdd(1))
                    {
                        if ((int)(new HTuple(((((hv_Amplitude.TupleSelect(hv_j))).TupleAbs())).TupleGreater(
                            hv_t))) != 0)
                        {

                            hv_tRow = hv_RowEdge.TupleSelect(hv_j);
                            hv_tCol = hv_ColEdge.TupleSelect(hv_j);
                            hv_t = ((hv_Amplitude.TupleSelect(hv_j))).TupleAbs();
                        }
                    }
                    //把找到的边缘保存在输出数组
                    if ((int)(new HTuple(hv_t.TupleGreater(0))) != 0)
                    {
                        hv_ResultRow = hv_ResultRow.TupleConcat(hv_tRow);
                        hv_ResultColumn = hv_ResultColumn.TupleConcat(hv_tCol);
                    }
                }

                ho_RegionLines.Dispose();
                ho_Rectangle.Dispose();
                ho_Arrow1.Dispose();

                return;
            }
            catch (HalconException HDevExpDefaultException)
            {
                ho_RegionLines.Dispose();
                ho_Rectangle.Dispose();
                ho_Arrow1.Dispose();

                throw HDevExpDefaultException;
            }
        }


        public void gen_arrow_contour_xld(out HObject ho_Arrow, HTuple hv_Row1, HTuple hv_Column1,
          HTuple hv_Row2, HTuple hv_Column2, HTuple hv_HeadLength, HTuple hv_HeadWidth)
        {
            // Stack for temporary objects 
            HObject[] OTemp = new HObject[20];
            long SP_O = 0;

            // Local iconic variables 

            HObject ho_TempArrow = null;


            // Local control variables 

            HTuple hv_Length, hv_ZeroLengthIndices, hv_DR;
            HTuple hv_DC, hv_HalfHeadWidth, hv_RowP1, hv_ColP1, hv_RowP2;
            HTuple hv_ColP2, hv_Index;

            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_Arrow);
            HOperatorSet.GenEmptyObj(out ho_TempArrow);

            try
            {
                //This procedure generates arrow shaped XLD contours,
                //pointing from (Row1, Column1) to (Row2, Column2).
                //If starting and end point are identical, a contour consisting
                //of a single point is returned.
                //
                //input parameteres:
                //Row1, Column1: Coordinates of the arrows' starting points
                //Row2, Column2: Coordinates of the arrows' end points
                //HeadLength, HeadWidth: Size of the arrow heads in pixels
                //
                //output parameter:
                //Arrow: The resulting XLD contour
                //
                //The input tuples Row1, Column1, Row2, and Column2 have to be of
                //the same length.
                //HeadLength and HeadWidth either have to be of the same length as
                //Row1, Column1, Row2, and Column2 or have to be a single element.
                //If one of the above restrictions is violated, an error will occur.
                //
                //
                //Init
                ho_Arrow.Dispose();
                HOperatorSet.GenEmptyObj(out ho_Arrow);
                //
                //Calculate the arrow length
                HOperatorSet.DistancePp(hv_Row1, hv_Column1, hv_Row2, hv_Column2, out hv_Length);
                //
                //Mark arrows with identical start and end point
                //(set Length to -1 to avoid division-by-zero exception)
                hv_ZeroLengthIndices = hv_Length.TupleFind(0);
                if ((int)(new HTuple(hv_ZeroLengthIndices.TupleNotEqual(-1))) != 0)
                {
                    hv_Length[hv_ZeroLengthIndices] = -1;
                }
                //
                //Calculate auxiliary variables.
                hv_DR = (1.0 * (hv_Row2 - hv_Row1)) / hv_Length;
                hv_DC = (1.0 * (hv_Column2 - hv_Column1)) / hv_Length;
                hv_HalfHeadWidth = hv_HeadWidth / 2.0;
                //
                //Calculate end points of the arrow head.
                hv_RowP1 = (hv_Row1 + ((hv_Length - hv_HeadLength) * hv_DR)) + (hv_HalfHeadWidth * hv_DC);
                hv_ColP1 = (hv_Column1 + ((hv_Length - hv_HeadLength) * hv_DC)) - (hv_HalfHeadWidth * hv_DR);
                hv_RowP2 = (hv_Row1 + ((hv_Length - hv_HeadLength) * hv_DR)) - (hv_HalfHeadWidth * hv_DC);
                hv_ColP2 = (hv_Column1 + ((hv_Length - hv_HeadLength) * hv_DC)) + (hv_HalfHeadWidth * hv_DR);
                //
                //Finally create output XLD contour for each input point pair
                for (hv_Index = 0; (int)hv_Index <= (int)((new HTuple(hv_Length.TupleLength())) - 1); hv_Index = (int)hv_Index + 1)
                {
                    if ((int)(new HTuple(((hv_Length.TupleSelect(hv_Index))).TupleEqual(-1))) != 0)
                    {
                        //Create_ single points for arrows with identical start and end point
                        ho_TempArrow.Dispose();
                        HOperatorSet.GenContourPolygonXld(out ho_TempArrow, hv_Row1.TupleSelect(
                            hv_Index), hv_Column1.TupleSelect(hv_Index));
                    }
                    else
                    {
                        //Create arrow contour
                        ho_TempArrow.Dispose();
                        HOperatorSet.GenContourPolygonXld(out ho_TempArrow, ((((((((((hv_Row1.TupleSelect(
                            hv_Index))).TupleConcat(hv_Row2.TupleSelect(hv_Index)))).TupleConcat(
                            hv_RowP1.TupleSelect(hv_Index)))).TupleConcat(hv_Row2.TupleSelect(hv_Index)))).TupleConcat(
                            hv_RowP2.TupleSelect(hv_Index)))).TupleConcat(hv_Row2.TupleSelect(hv_Index)),
                            ((((((((((hv_Column1.TupleSelect(hv_Index))).TupleConcat(hv_Column2.TupleSelect(
                            hv_Index)))).TupleConcat(hv_ColP1.TupleSelect(hv_Index)))).TupleConcat(
                            hv_Column2.TupleSelect(hv_Index)))).TupleConcat(hv_ColP2.TupleSelect(
                            hv_Index)))).TupleConcat(hv_Column2.TupleSelect(hv_Index)));
                    }
                    OTemp[SP_O] = ho_Arrow.CopyObj(1, -1);
                    SP_O++;
                    ho_Arrow.Dispose();
                    HOperatorSet.ConcatObj(OTemp[SP_O - 1], ho_TempArrow, out ho_Arrow);
                    OTemp[SP_O - 1].Dispose();
                    SP_O = 0;
                }
                ho_TempArrow.Dispose();

                return;
            }
            catch (HalconException HDevExpDefaultException)
            {
                ho_TempArrow.Dispose();

                throw HDevExpDefaultException;
            }
        }


    }
}
